// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
//
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.ui.prefs.connectivity;

import java.io.BufferedInputStream;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.dengues.commons.connectivity.IConnectivitySettingsConstants;
import org.dengues.commons.utils.DriverUtil;
import org.dengues.core.DenguesCorePlugin;
import org.dengues.core.ExceptionOperation;
import org.dengues.core.IDesignerCoreService;
import org.dengues.core.components.EGlobalComponentNames;
import org.dengues.core.components.IXMLComponent;
import org.dengues.core.connectivity.IConnectivityManager;
import org.dengues.core.connectivity.IConnectivityProperty;
import org.dengues.ui.prefs.connectivity.models.ConnectivityProperty;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

import dengues.system.ConnectivityUtils;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 2007-11-25 qiang.zhang $
 * 
 */
public class ConnectivityManager implements IConnectivityManager {

    private static ConnectivityManager instance;

    private Connection connection;

    private String schema;

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getConnection".
     * 
     * @param properties
     * @return
     */
    public String getConnection(final Map properties, final boolean isPrompt, final boolean isNestedDriver) {
        final StringBuilder message = new StringBuilder(org.dengues.ui.i18n.Messages.getString("ConnectivityManager.title")); //$NON-NLS-1$
        boolean isFail = false;
        connection = null;
        schema = (String) properties.get(EConnectivityProperties.PROP_ID_SCHEMA.getPropId());
        String rootpath = (String) properties.get(EConnectivityProperties.PROP_ID_ROOTPATH.getPropId());
        if (rootpath != null && !"".equals(rootpath)) { //$NON-NLS-1$
            System.setProperty("derby.system.home", rootpath); //$NON-NLS-1$
        }
        if (isNestedDriver) {
            String driver = (String) properties.get(EConnectivityProperties.PROP_ID_DRIVER.getPropId());
            String url = (String) properties.get(EConnectivityProperties.PROP_ID_URL.getPropId());
            String user = (String) properties.get(EConnectivityProperties.PROP_ID_USER.getPropId());
            String password = (String) properties.get(EConnectivityProperties.PROP_ID_PASSWORD.getPropId());
            try {
                Class.forName(driver);
                connection = java.sql.DriverManager.getConnection(url, user, password);
            } catch (Exception ex) {
                message.delete(0, message.length());
                message.append(ex.getMessage());
                isFail = true;
            }
        } else {
            String[] jars = XMLFileManager.parseString((String) properties.get(IConnectivitySettingsConstants.PROP_DEFN_JARLIST));
            String dClass = (String) properties.get(EConnectivityProperties.PROP_ID_DRIVER.getPropId());
            try {
                Class clazz = DriverUtil.getDriverClassFromJars(jars, dClass);
                if (clazz == null) {
                    if (dClass == null) {
                        throw new RuntimeException(org.dengues.ui.i18n.Messages.getString("ConnectivityManager.driver")); //$NON-NLS-1$
                    }
                    clazz = Class.forName(dClass);
                }
                if (clazz != null) {
                    Driver driver = (Driver) clazz.newInstance();
                    Properties properties2 = new Properties();
                    String user = (String) properties.get(EConnectivityProperties.PROP_ID_USER.getPropId());
                    if (user != null) {
                        properties2.setProperty("user", user); //$NON-NLS-1$
                        String pwd = (String) properties.get(EConnectivityProperties.PROP_ID_PASSWORD.getPropId());
                        properties2.setProperty("password", pwd == null ? "" : pwd); //$NON-NLS-1$ //$NON-NLS-2$
                    }
                    String url = (String) properties.get(EConnectivityProperties.PROP_ID_URL.getPropId());
                    connection = driver.connect(url, properties2);
                }
            } catch (final Exception ex) {
                message.delete(0, message.length());
                message.append(ex.getMessage());
                isFail = true;
            }
        }
        if (isPrompt && isFail) {
            Display.getDefault().asyncExec(new Runnable() {

                /*
                 * (non-Javadoc)
                 * 
                 * @see java.lang.Runnable#run()
                 */
                public void run() {
                    ExceptionOperation.openErrorDilogWithDetail(new Shell(), org.dengues.ui.i18n.Messages
                            .getString("ConnectivityManager.error"), message.toString()); //$NON-NLS-1$
                }
            });
        }
        return message.toString();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getConnection".
     * 
     * @param shell
     * @param properties
     */
    public void testConnection(Shell shell, final Properties properties, final boolean isNestedDriver) {
        ProgressMonitorDialog pmd = new ProgressMonitorDialog(shell);
        try {
            pmd.run(true, true, new IRunnableWithProgress() {

                public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                    final StringBuilder builder = new StringBuilder();
                    try {
                        monitor.beginTask("", IProgressMonitor.UNKNOWN); //$NON-NLS-1$
                        if (isNestedDriver) {
                            String driver = properties.getProperty(EConnectivityProperties.PROP_ID_DRIVER.getPropId());
                            String url = properties.getProperty(EConnectivityProperties.PROP_ID_URL.getPropId());
                            String rootpath = properties.getProperty(EConnectivityProperties.PROP_ID_ROOTPATH.getPropId());
                            String user = properties.getProperty(EConnectivityProperties.PROP_ID_USER.getPropId());
                            String password = properties.getProperty(EConnectivityProperties.PROP_ID_PASSWORD.getPropId());
                            builder.append(ConnectivityUtils.testConnection(driver, url, user, password, rootpath));
                        } else {
                            final IDesignerCoreService designerCoreService = DenguesCorePlugin.getDefault()
                                    .getDesignerCoreService();
                            final IXMLComponent component = designerCoreService.getComponentsFactory().getComponent(
                                    EGlobalComponentNames.ZTESTCONNECTION.getName());
                            final Process process = designerCoreService.launchShadowProcess(component, properties);
                            if (process == null) {
                                return;
                            }

                            while (true) {
                                int read = 0;
                                byte[] bytes = new byte[8192];
                                if (process.getInputStream().available() > 0) {
                                    BufferedInputStream stream = new BufferedInputStream(process.getInputStream(), 8192);
                                    while (read >= 0) {
                                        read = stream.read(bytes);
                                        if (read > 0) {
                                            builder.append(new String(bytes, 0, read));
                                        }
                                    }
                                    break;
                                }
                                if (process.getErrorStream().available() > 0) {
                                    BufferedInputStream stream = new BufferedInputStream(process.getErrorStream(), 8192);
                                    while (read >= 0) {
                                        read = stream.read(bytes);
                                        if (read > 0) {
                                            builder.append(new String(bytes, 0, read));
                                        }
                                    }
                                    break;
                                }
                                if (monitor.isCanceled()) {
                                    return;
                                }
                                Thread.sleep(100);
                            }
                        }
                        if (!monitor.isCanceled()) {
                            Display.getDefault().asyncExec(new Runnable() {

                                public void run() {
                                    MessageDialog.openInformation(new Shell(), "", builder.toString());//$NON-NLS-1$
                                }
                            });
                        }
                    } catch (Exception e1) {
                        e1.printStackTrace();
                    }
                }
            });
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getConnection".
     * 
     * @return
     */
    public Connection getConnection() {
        return connection;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "closeConnection".
     */
    public void closeConnection() {
        if (connection != null) {
            try {
                boolean b = connection.isClosed();
                if (!b) {
                    connection.close();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
        connection = null;
        schema = null;
    }

    /**
     * Getter for schema.
     * 
     * @return the schema
     */
    public String getSchema() {
        return schema;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.connectivity.IConnectivityManager#getAllConnProperties()
     */
    public List<IConnectivityProperty> getAllConnProperties() {
        List<IConnectivityProperty> list = new ArrayList<IConnectivityProperty>();
        XMLFileManager.setFileName(IConnectivitySettingsConstants.CONNECTIVITY_FILE);
        try {
            ConnectivityProperty[] loadPropertySets = XMLFileManager.loadPropertySets();
            for (ConnectivityProperty connectivityProperty : loadPropertySets) {
                list.add(connectivityProperty);
            }
        } catch (CoreException ex) {
            ex.printStackTrace();
        }
        return list;
    }

    /**
     * Getter for instance.
     * 
     * @return the instance
     */
    public static ConnectivityManager getInstance() {
        if (instance == null) {
            instance = new ConnectivityManager();
        }
        return instance;
    }
}
